﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using Boxi.EventArguments;
using Boxi.Model;

namespace Boxi.ViewModel
{

    public abstract class  MoveView : INotifyPropertyChanged
    {
        #region Fields

        #endregion
        #region Events
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<PointAssignedEventArgs> OnPointAssigned;
        public event EventHandler<MoveMadeEventArgs> OnMoveMade;
        public event EventHandler<EventArgs> OnActivationComplete;
        #endregion
        #region Enumerations
        /// <summary>
        /// 
        /// </summary>
        public enum WaitingForType
        {
            Turn,
            Input,
            Timer
        }
        #endregion
        #region Properties
        /// <summary>
        /// 
        /// </summary>
        public GameView Game
        {
            get;
            private set;
        }

        public Byte MoveID
        {
            get;
            private set;
        }

        /// <summary>
        /// 
        /// </summary>
        public WaitingForType WaitingFor
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        public SolidColorBrush Color
        {
            get;
            set;
        }


        /// <summary>
        /// 
        /// </summary>
        public Byte TouchTicks
        {
            get
            {
                return _touchTicks;
            }
            set
            {
                _touchTicks = value;
                NotifyPropertyChanged("TouchTicks");
            }
        }
        private Byte _touchTicks;

        /// <summary>
        /// 
        /// </summary>
        public Rectangle ElementUI
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public Rectangle ElementTouch
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public Polygon ElementTouchUI
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public Point Location
        {
            get;
            private set;
        }

        /// <summary>
        /// 
        /// </summary>
        public DispatcherTimer TouchTimer
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public DispatcherTimer AssignTimer
        {
            get;
            set;
        }
        #endregion
        #region Constructors
        /// <summary>
        /// 
        /// </summary>
        /// <param name="game"></param>
        /// <param name="moveID"></param>
        /// <param name="location"></param>
        /// <param name="elementUI"></param>
        /// <param name="elementTouch"></param>
        /// <param name="elementTouchUI"></param>
        public MoveView(GameView game, Byte moveID, Point location, Rectangle elementUI, Rectangle elementTouch, Polygon elementTouchUI)
        {
            MoveID = moveID;
            Game = game;
            ElementUI = elementUI;
            ElementTouch = elementTouch;
            ElementTouchUI = elementTouchUI;
            Location = location;

            TouchTimer = new DispatcherTimer();
            TouchTimer.Interval = new TimeSpan(0, 0, 0, 0, 30);

            AssignTimer = new DispatcherTimer();
            AssignTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);

            ElementTouch.MouseEnter += (o, e) =>
            {
                if (Game.MoveOptions[moveID - 1].MoveMadeOrder > 0 || Game.CurrentTurn.Player.PlayerData.TypeOfPlayer != PlayerModel.PlayerType.Human || Game.IsAutoMove)
                    return;

                ActivationBegin();
            };
            ElementTouch.MouseLeave += (o, e) =>
            {
                if (Game.MoveOptions[moveID - 1].MoveMadeOrder > 0 || Game.CurrentTurn.Player.PlayerData.TypeOfPlayer != PlayerModel.PlayerType.Human)
                    return;

                if (Game.CurrentTouch == this && TouchTicks >= 10)
                    AssignBegin();
                else
                    Deactivate();
            };
            TouchTimer.Tick += (o, e) =>
            {
                if (Game.MoveOptions[moveID - 1].MoveMadeOrder > 0 || Game.CurrentTouch != this || Game.CurrentTurn.Player.PlayerData.TypeOfPlayer != PlayerModel.PlayerType.Human)
                    return;

                if (TouchTicks >= 10)
                    ActivationComplete();
                else
                    Activating();
            };
            AssignTimer.Tick += (o, e) =>
            {
                if (Game.MoveOptions[moveID - 1].MoveMadeOrder > 0 || Game.CurrentTurn.Player.PlayerData.TypeOfPlayer != PlayerModel.PlayerType.Human)
                    return;

                if (Game.CurrentTouch == this && TouchTicks >= 10){
                    Assign();
                }else{
                    Deactivate();
                }
            };
        }
        #endregion
        #region Methods
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
        #region Action Handlers
        public void ActivationBegin()
        {
            Game.CurrentTouch = this;
            TouchTicks = 0;

            ElementTouchUI.Fill = Game.GetForegroundColor();
            ElementTouchUI.Visibility = Visibility.Visible;
            ElementTouchUI.Opacity = 0.18d;
            ElementTouch.Fill = Game.CurrentTurn.Player.Color;
            ElementTouch.Opacity = 0.18d;

            TouchTimer.Start();
            WaitingFor = WaitingForType.Timer;
        }
        public void Activating()
        {
            TouchTicks += 1;
            ElementTouchUI.Opacity = ElementTouchUI.Opacity + 0.05d;
        }
        public void ActivationComplete()
        {
            ElementTouchUI.Fill = Game.CurrentTurn.Player.Color;
            if (TouchTimer.IsEnabled)
                TouchTimer.Stop();

            if (OnActivationComplete != null)
                OnActivationComplete.Invoke(this, null);
        }
        public void Deactivate()
        {
            if (TouchTimer.IsEnabled)
                TouchTimer.Stop();

            if (AssignTimer.IsEnabled)
                AssignTimer.Stop();

            TouchTicks = 0;
            Game.CurrentTouch = null;

            ElementTouch.Opacity = 0d;
            ElementTouchUI.Visibility = Visibility.Collapsed;
            ElementTouchUI.Fill = new SolidColorBrush(Colors.Transparent);
            ElementUI.Fill = Game.GetForegroundColor();
            ElementUI.Opacity = (Game.Theme == GameModel.ThemeType.Arcade) ? 0.18d : 0.04d;

        }
        public void AssignBegin()
        {
            AssignTimer.Start();
        }
        public MoveHistoryModel Assign(Boolean isReloading = false)
        {
            if (AssignTimer.IsEnabled)
                AssignTimer.Stop();

            TouchTicks = 0;
            Game.CurrentTouch = null;

            ElementTouch.Opacity = 0d;
            ElementTouchUI.Visibility = Visibility.Collapsed;
            ElementTouchUI.Fill = new SolidColorBrush(Colors.Transparent);
            ElementUI.Fill = Game.CurrentTurn.Player.Color;
            ElementUI.Opacity = 0.62d;

            var moveMade = Game.MoveHistory[Game.MoveOptions.SetMove(Game.MoveHistory, MoveID, Game.CurrentTurn.Player.PlayerData.PlayerID, Game.GameData) - 1];
            if (moveMade.Points.Length > 0)
            {
                Int32 uiPoints = 0;
                foreach (EventHandler<PointAssignedEventArgs> handler in OnPointAssigned.GetInvocationList())
                {
                    PointAssignedEventArgs maea = new PointAssignedEventArgs();
                    handler(this, maea);
                    if (maea.PointAssigned)
                        uiPoints += 1;
                }
                if (uiPoints != moveMade.Points.Length)
                    throw new Exception("This should never happen");
            }
            Game.CurrentTurn.Moves.Add(this);
            Game.CurrentTurn.Player.PlayerData.Moves += 1;
            Game.CurrentTurn.Player.PlayerData.Points += (Byte)moveMade.Points.Length;

            if (OnMoveMade != null && !isReloading)
                OnMoveMade.Invoke(this, new MoveMadeEventArgs(this, moveMade.Points, true));

            if (moveMade.Points.Length > 0)
                WaitingFor = WaitingForType.Turn;

            return moveMade;
        }
        #endregion
    }
}
